﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using ScrumTable.Common.Collections;
using ScrumTable.Common.Monitoring;
using ScrumTable.Common.Security;
using ScrumTable.Common.Threading;
using ScrumTable.DL.Data.Common;
using ScrumTable.DL.Data.Generic.Cache;
using ScrumTable.DL.Data.Generic.Config.Driver;
using ScrumTable.DL.Data.Generic.Test.Mocks;
using ScrumTable.DL.Data.Generic.Test.Mocks.Config.Driver;
using ScrumTable.DL.Data.Generic.Test.Mocks.Config.Schema;

#endregion

namespace ScrumTable.DL.Data.Generic.Test
{
    /// <summary>
    /// This is the test class for DataContext class.
    /// </summary>
    [TestClass]
    public class DataContextTest
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #endregion

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new DataContextTest instance.
        /// </summary>
        public DataContextTest()
        {
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        [TestMethod]
        public void TestChangeEvents()
        {
            // instantiate data layer mock
            DataLoaderMock dataLoader = new DataLoaderMock();
            GenericDataContextStub context = new GenericDataContextStub(
                dataLoader,
                new DataSaverStub(CacheSavePairState.Saved),
                new DataContextInfoStub(
                    TestContext.TestDir,
                    dci => new GenericDataSchemaSelectorStub(dci),
                    dci => new GenericDriverConfigSelectorStub(dci)));
            dataLoader.Schema = context.Schema;
            context.Connection.Connect(
                new ConnectionInformationManager(ConnectionInformation.Empty),
                r => { },
                null);

            bool beginUpdateFired = false;
            bool endUpdateFired = false;
            context.BeginUpdate += (s, e) => beginUpdateFired = true;
            context.EndUpdate += (s, e) => endUpdateFired = true;

            // import data into first create project instance
            context.ImportData(new ValueChain<string>(dataLoader.FirstProjectUniqueId), new NullDataImportMonitor());
            Assert.IsFalse(beginUpdateFired);
            Assert.IsFalse(endUpdateFired);

            // export changed data (there's no change)
            CacheDataChanges export = context.ExportChanges();
            Assert.IsNotNull(export);
            Assert.IsFalse(beginUpdateFired);
            Assert.IsFalse(endUpdateFired);
            export.RemoveDirtyFlags();

            // import changes, this should change the beginUpdateFired/endUpdateFired flags
            context.ImportChanges(export);
            Assert.IsTrue(beginUpdateFired);
            Assert.IsTrue(endUpdateFired);
        }

        [TestMethod]
        public void TestCreateWithStub()
        {
            DataLoaderStub dataLoader = new DataLoaderStub();
            GenericDataContextStub context = new GenericDataContextStub(
                dataLoader,
                new DataSaverStub(CacheSavePairState.Saved),
                new DataContextInfoStub(
                    TestContext.TestDir,
                    dci => new GenericDataSchemaSelectorStub(dci),
                    dci => new GenericDriverConfigSelectorStub(dci)));
            dataLoader.Schema = context.Schema;
            bool callbackAvailable = false;
            context.Connection.Connect(
                new ConnectionInformationManager(),
                result => callbackAvailable = (result is DataResult && !((DataResult)result).HasError),
                null );
            Assert.IsTrue(callbackAvailable);
            Assert.IsTrue(dataLoader.LoadConnectionDataCalled);
            context.ImportData(ValueChain<string>.Empty, new NullDataImportMonitor());
            Assert.IsTrue(dataLoader.LoadInitialDataCalled);
        }

        [TestMethod]
        public void TestImportData()
        {
            DataLoaderMock dataLoader = new DataLoaderMock();
            GenericDataContextStub context = new GenericDataContextStub(
                dataLoader,
                new DataSaverStub(CacheSavePairState.Saved),
                new DataContextInfoStub(
                    TestContext.TestDir,
                    dci => new GenericDataSchemaSelectorStub(dci),
                    dci => new GenericDriverConfigSelectorStub(dci)));
            dataLoader.Schema = context.Schema;
            context.Connection.Connect(
                new ConnectionInformationManager(ConnectionInformation.Empty),
                r =>  { },
                null );

            ICollection<IDataObject> projects = context.Storage[context.Schema.ProjectSchema].GetAll(ValueChain<string>.Empty);
            IDataObject firstProject = (from p in projects
                                       where p.Id == dataLoader.FirstProjectUniqueId
                                       select p).First();

            CacheProject project = context.DataCache.Projects[dataLoader.FirstProjectUniqueId];
            
            context.ImportData(new ValueChain<string>(firstProject.Id), new NullDataImportMonitor());

            Assert.AreEqual(
                ResourceManager.Project1IterationCount,
                context.Storage[context.Schema.IterationSchema].GetAll(new ValueChain<string>(project.UniqueId)).Count);
            Assert.AreEqual(
                ResourceManager.Project1MemberCount,
                context.Storage[context.Schema.MemberSchema].GetAll(new ValueChain<string>(project.UniqueId)).Count);
            Assert.AreEqual(
                ResourceManager.Project1Iteration1UserStoryCount,
                context.Storage[context.Schema.UserStorySchema].GetAll(dataLoader.Resources.GetIterationChain(project, ResourceManager.Iteration1Id)).Count);
            Assert.AreEqual(
                ResourceManager.Project1UserStory1TaskCount,
                context.Storage[context.Schema.TaskSchema].GetAll(dataLoader.Resources.GetUserStoryChain(project, ResourceManager.UserStory1Id)).Count);
            Assert.AreEqual(
                ResourceManager.Project1UserStory2TaskCount,
                context.Storage[context.Schema.TaskSchema].GetAll(dataLoader.Resources.GetUserStoryChain(project, ResourceManager.UserStory2Id)).Count);
            Assert.AreEqual(
                ResourceManager.Project1Iteration1UserStory3TaskCount,
                context.Storage[context.Schema.TaskSchema].GetAll(dataLoader.Resources.GetUserStoryChain(project, ResourceManager.Iteration1Id, ResourceManager.UserStory3Id)).Count);
        }

        [TestMethod]
        public void TestExportData()
        {
            TestExportData(true, CacheSavePairState.Saved);
        }

        [TestMethod]
        public void TestExportDataWithUnAccepted()
        {
            TestExportData(false, CacheSavePairState.Error);
        }

        private void TestExportData(bool acceptData, CacheSavePairState state)
        {
            bool dataAccepted = !acceptData;
            DataLoaderMock dataLoader = new DataLoaderMock();
            GenericDataContextStub context = new GenericDataContextStub(
                dataLoader,
                new DataSaverStub(state),
                new DataContextInfoStub(
                    TestContext.TestDir,
                    dci => new GenericDataSchemaSelectorStub(dci),
                    dci => new GenericDriverConfigSelectorStub(dci)));
            dataLoader.Schema = context.Schema;
            context.Connection.Connect(
                new ConnectionInformationManager(ConnectionInformation.Empty),
                r => { },
                null);
            context.ImportData(new ValueChain<string>(dataLoader.FirstProjectUniqueId), new NullDataImportMonitor());
            context.DataCache.Projects.First().Iterations.First().StartDate = DateTime.Now;
            context.ExportData(result => dataAccepted = ((ICancellableDataResult)result).DataAccepted);
            Assert.AreEqual(acceptData, dataAccepted);
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}
